<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006~2016 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------

namespace think;

\think\Loader::import('controller/Jump', TRAIT_PATH, EXT);

use app\backend\model\LoginLog;
use think\Exception;
use think\exception\ValidateException;
use app\backend\model\Member;

class Controller
{
    use \traits\controller\Jump;

    // 视图类实例
    protected $view;
    // Request实例
    protected $request;
    // 验证失败是否抛出异常
    protected $failException = false;
    // 是否批量验证
    protected $batchValidate = false;

    /**
     * 前置操作方法列表
     * @var array $beforeActionList
     * @access protected
     */
    protected $beforeActionList = [];

    /**
     * 架构函数
     * @param Request    $request     Request对象
     * @access public
     */
    public function __construct(Request $request = null)
    {
        if (is_null($request)) {
            $request = Request::instance();
        }
        $this->view    = View::instance(Config::get('template'), Config::get('view_replace_str'));
        $this->request = $request;

        // 控制器初始化
        $this->_initialize();

        // 前置操作方法
        if ($this->beforeActionList) {
            foreach ($this->beforeActionList as $method => $options) {
                is_numeric($method) ?
                $this->beforeAction($options) :
                $this->beforeAction($method, $options);
            }
        }
    }

    // 初始化
    protected function _initialize()
    {

    }

    /**
     * 判断是不是已经登陆
     * @author dwer
     * @DateTime 2016-02-16T13:55:07+0800
     *
     * @param    string  $type 指定请求类型
     *                         ajax : ajax请求
     *                         html : 页面请求
     *                         auto : 自动判定
     * @return   mixed
     *
     */
    public function isLogin($type = 'auto') {
        $typeArr = array('ajax', 'html');

        if($type == 'auto') {
            $r = isset($_SERVER['HTTP_X_REQUESTED_WITH']) ? strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) : '';
            if($r == 'xmlhttprequest') {
                $type = 'ajax';
            } else {
                $type = 'html';
            }
        }

        if(!in_array($type, $typeArr)) {
            $type = 'ajax';
        }

        //判断登录
        $memberSID = isset($_SESSION['mid']) && $_SESSION['mid'] ? $_SESSION['mid'] : false;

        if($type == 'ajax') {
            if($memberSID) {
                $res = $this->auth_expired_check($memberSID);
                if (!$res) {
                    $this->apiReturn(102, [], '账号已过期，请重新登录');
                }
                return $memberSID;
            } else {
                $this->apiReturn(102, [], '未登录');
            }
        } else {
            if($memberSID) {
                if (!$this->auth_expired_check($memberSID)) {
                    alert('账号已过期，请重新登录', config('login_url'));
                }
                return $memberSID;
            } else {
                //跳转到首页
                alert('请先登录', config('login_url'));
            }
        }
    }

    /**
     * 检测登录情况
     * @author wuhao
     * @date   2017-04-25
     *
     * @return mixed
     */
    public function checkLoginStatus()
    {
        if (isset($_SESSION['mid'])) {
            return $_SESSION['mid'];
        } else {
            return false;
        }
    }

    /**
     * 修改手机号更新session
     * @author wuhao
     * @date   2017-05-12
     *
     * @param $newMobile 新手机号
     * @return mixed
     */
    public function changeMobileSession($newMobile)
    {
        $_SESSION['mobile'] = $newMobile;
    }

    /**
     * 获取登录信息
     * @author wuhao
     * @date   2017-04-19
     *
     * @param  string  $type 指定请求类型
     *                  ajax : ajax请求
     *                  html : 页面请求
     *                  auto : 自动判定
     * @return array
     */
    public function getLoginInfo($type = 'auto') {
        //判断是否登录
        $this->isLogin($type);

        $loginInfo = [
            'mid'      => $_SESSION['mid'],
            'p_mid'    => $_SESSION['p_mid'],
            'username' => $_SESSION['username'],
            'mobile'   => $_SESSION['mobile'],
            'nickname' => $_SESSION['nickname'],
            'dtype'    => $_SESSION['dtype'],
            'p_dtype'  => $_SESSION['p_dtype'],
            'avatar'   => $_SESSION['avatar'],
        ];

        return $loginInfo;
    }
    /**
     * [auth_password_check 动态密码校验]
     * 应用场景：修改密码后，使其它地方登录的账号进行操作时使账号失效
     * @return [type] [description]
     */
    protected function auth_password_check(){
        $user = new Member();
        $where_query = array(
            'username' => session('username'),
            'password' => session('password'),
            'status'   => 1
        );
        $user = $user->where($where_query)->find();
        if (!$user) {
            //注销当前账号
            unset($_SESSION);
            alert('登录失效:用户密码已更改',config('login_url'));
        }
    }

    /**
     * [auth_expired_check 登录时间校验
     * 应用场景：主要是在他人电脑上登陆后，忘了登出
     * @return [type] [description]
     */
    protected function auth_expired_check($memberSID){
        $loginLog = new LoginLog();
        $log = $loginLog->getLastLoginLog($memberSID);
        if (time() > config('auth_expired_time')+ $log['login_time']) { //登录超时
            //注销当前账号
            unset($_SESSION);
            session_destroy();
            return false;
        }
        return true;
    }

    /**
     * 前置操作
     * @access protected
     * @param string    $method     前置操作方法名
     * @param array     $options    调用参数 ['only'=>[...]] 或者['except'=>[...]]
     */
    protected function beforeAction($method, $options = [])
    {
        if (isset($options['only'])) {
            if (is_string($options['only'])) {
                $options['only'] = explode(',', $options['only']);
            }
            if (!in_array($this->request->action(), $options['only'])) {
                return;
            }
        } elseif (isset($options['except'])) {
            if (is_string($options['except'])) {
                $options['except'] = explode(',', $options['except']);
            }
            if (in_array($this->request->action(), $options['except'])) {
                return;
            }
        }

        if (method_exists($this, $method)) {
            call_user_func([$this, $method]);
        }
    }

    /**
     * 加载模板输出
     * @access protected
     * @param string    $template 模板文件名
     * @param array     $vars     模板输出变量
     * @param array     $replace     模板替换
     * @param array     $config     模板参数
     * @return mixed
     */
    protected function fetch($template = '', $vars = [], $replace = [], $config = [])
    {
        return $this->view->fetch($template, $vars, $replace, $config);
    }

    /**
     * 渲染内容输出
     * @access protected
     * @param string    $content 模板内容
     * @param array     $vars     模板输出变量
     * @param array     $replace 替换内容
     * @param array     $config     模板参数
     * @return mixed
     */
    protected function display($content = '', $vars = [], $replace = [], $config = [])
    {
        return $this->view->display($content, $vars, $replace, $config);
    }

    /**
     * 模板变量赋值
     * @access protected
     * @param mixed     $name  要显示的模板变量
     * @param mixed     $value 变量的值
     * @return void
     */
    protected function assign($name, $value = '')
    {
        $this->view->assign($name, $value);
    }

    /**
     * 初始化模板引擎
     * @access protected
     * @param array|string $engine 引擎参数
     * @return void
     */
    protected function engine($engine)
    {
        $this->view->engine($engine);
    }

    /**
     * 设置验证失败后是否抛出异常
     * @access protected
     * @param bool $fail 是否抛出异常
     * @return $this
     */
    protected function validateFailException($fail = true)
    {
        $this->failException = $fail;
        return $this;
    }

    /**
     * 验证数据
     * @access protected
     * @param array        $data     数据
     * @param string|array $validate 验证器名或者验证规则数组
     * @param array        $message  提示信息
     * @param bool         $batch    是否批量验证
     * @param mixed        $callback 回调方法（闭包）
     * @return array|string|true
     * @throws ValidateException
     */
    protected function validate($data, $validate, $message = [], $batch = false, $callback = null)
    {
        if (is_array($validate)) {
            $v = Loader::validate();
            $v->rule($validate);
        } else {
            if (strpos($validate, '.')) {
                // 支持场景
                list($validate, $scene) = explode('.', $validate);
            }
            $v = Loader::validate($validate);
            if (!empty($scene)) {
                $v->scene($scene);
            }
        }
        // 是否批量验证
        if ($batch || $this->batchValidate) {
            $v->batch(true);
        }

        if (is_array($message)) {
            $v->message($message);
        }

        if ($callback && is_callable($callback)) {
            call_user_func_array($callback, [$v, &$data]);
        }

        if (!$v->check($data)) {
            if ($this->failException) {
                throw new ValidateException($v->getError());
            } else {
                return $v->getError();
            }
        } else {
            return true;
        }
    }

    /**
     * 接口数据返回
     * @author dwer
     * @DateTime 2016-02-16T13:48:27+0800
     *
     * @param    int                      $code   返回码
     * @param    array                    $data   接口返回数据
     * @param    string                   $msg    错误说明，默认为空
     * @param    boolean                  $object 当data为空时，是否返回空对象
     * @return
     */
    public function apiReturn($code, $data = array(), $msg = '', $object = false) {

        if ($data == [] && $object) {
            $data = new \stdClass;
        }

        $data = array(
            'code' => $code,
            'data' => $data,
            'msg'  => $msg
        );

        header('Content-type:text/json');
        $res = json_encode($data, JSON_UNESCAPED_UNICODE);
        echo $res;
        exit();
    }


}
